#include "curveplot.h"

#include <QGridLayout>
#include <QRandomGenerator>

#include "qcustomplot.h"
/**
 * @brief 生成随机背景色（HSL颜色空间）
 * @param maxLightness 最大亮度值(0-255)，默认200避免过浅
 * @param alpha 透明度(0-255)，默认不透明
 * @return 适合作为背景的QColor对象
 *
 * 该实现采用HSL颜色空间生成更自然的随机色
 * 通过限制亮度范围确保背景可读性
 */
QColor randomBackgroundColor(int maxLightness = 200, int alpha = 255)
{
    Q_ASSERT(maxLightness >= 0 && maxLightness <= 255);

    auto* generator = QRandomGenerator::global();
    return QColor::fromHsl(
        generator->bounded(360),    // 色相0-359
        generator->bounded(50, 256),// 饱和度50-255（避免灰度色）
        generator->bounded(maxLightness),
        alpha
    );
}


CurvePlot::CurvePlot(QWidget *parent) : QWidget(parent)
{
    // 实例化画布
    m_customPlot = new QCustomPlot(this);
    QCustomPlot *customPlot = m_customPlot;
    // 绑定画布
    m_tracerManager = new TracerManager(m_customPlot, this);

    // OpenGL加速初始化（在父窗口构造函数中）
    m_customPlot->setOpenGl(true);
    if (!m_customPlot->openGl())
        qDebug() << "OpenGL加速未启用，回退到软件渲染";

    // 创建画布
    QGridLayout *layout = new QGridLayout(this);
    layout->setContentsMargins(2, 2, 2, 2);
    layout->addWidget(customPlot);
    this->setLayout(layout);
    this->setAttribute(Qt::WA_StyledBackground, true);  // 强制启用样式表背景绘制

    // 轴设置
    // 创建字体对象（Arial 字体，12号，加粗）
    m_axisFont = QFont("Arial", 12, QFont::Bold);
    // x轴
    customPlot->xAxis->setRange(1, 1, Qt::AlignRight);          // 设置轴刻度
    customPlot->xAxis->ticker()->setTickCount(8);               // 设置轴刻度数目
    customPlot->xAxis->setLabel(tr("timestamp"));                     // 设置轴标签
    customPlot->xAxis->setLabelFont(m_axisFont);
    // y轴
    customPlot->yAxis->setRange(2, 2, Qt::AlignRight);
    customPlot->yAxis->ticker()->setTickCount(5);
    customPlot->yAxis->setLabel(tr("data"));
    customPlot->yAxis->setLabelFont(m_axisFont);
    // 图表名称
    customPlot->xAxis2->setVisible(true);
    customPlot->xAxis2->setLabel(m_name);
    customPlot->xAxis2->setLabelFont(QFont("Arial", 16, QFont::Bold));
    customPlot->xAxis2->setTickLabelPadding(15);


    // 图例
    customPlot->legend->setFont(QFont("Arial", 10, QFont::Bold));  // 字体、字号、加粗
    customPlot->legend->setTextColor(Qt::black);                    // 文字颜色

    customPlot->legend->setVisible(true);                       // 显示
    customPlot->legend->setBrush(QColor(255, 255, 255, 50));   // 灰色透明
//    customPlot->legend->setBorderPen(Qt::NoPen);                // 边框隐藏
    customPlot->legend->setBorderPen(QPen(Qt::black, 1, Qt::DashLine));// 黑色，线宽1，虚线
    customPlot->legend->setWrap(4);                             // 设置4个图例自动换行
    customPlot->legend->setFillOrder(QCPLayoutGrid::foRowsFirst);    // 图例优先排序(foRowsFirst foColumnsFirst) foRowsFirst
    customPlot->axisRect()->insetLayout()->setInsetAlignment(0,Qt::AlignTop | Qt::AlignRight);//图例显示位置右上
    customPlot->plotLayout()->setRowStretchFactor(0, 0.001);            // 显示比例     0 0.001
    customPlot->axisRect()->setupFullAxesBox(true);// 设置基本坐标轴（左侧Y轴和下方X轴）可拖动、可缩放、曲线可选、legend可选、设置伸缩比例，使所有图例可见
    customPlot->setInteractions(QCP::iRangeDrag|QCP::iRangeZoom| QCP::iSelectAxes | QCP::iSelectLegend | QCP::iSelectPlottables);
    // 配置坐标轴显示并同步轴范围
    // 设置legend只能选择图例
    customPlot->legend->setSelectableParts(QCPLegend::spItems);

    // 设置图例与曲线同步选中
    bool isConnected = QObject::connect(customPlot, SIGNAL(selectionChangedByUser()), this, SLOT(selectionChanged()));
//    connect(m_customPlot, &QCustomPlot::selectionChangedByUser, this, &CurvePlot::selectionChanged);
//    bool isConnected = connect(m_customPlot, &QCustomPlot::selectionChangedByUser,
//                              this, &CurvePlot::selectionChanged);
    Q_ASSERT_X(isConnected, "Connection", "Signal/Slot binding failed!");

//    QWidget *widget = this;
//    QPalette palette = widget->palette();
//    QColor bgColor = randomBackgroundColor(220, 200); // 70%透明度
//    palette.setColor(QPalette::Window, bgColor); // 设置红色背景
//    widget->setAutoFillBackground(true);         // 必须启用自动填充
    //    widget->setPalette(palette);


    // 初始化定时器
    m_replotTimer = new QTimer(this);
    m_replotTimer->setInterval(m_intervalTime);
    connect(m_replotTimer, &QTimer::timeout, this, &CurvePlot::replotTimer_timeout);

    // 曲线数据存储路径
    QString appDir = QCoreApplication::applicationDirPath();
    QString dataFilePath = appDir + QString("/dataLog.txt");
    qDebug() << "dataFilePath: " << dataFilePath;
    m_dataBuffer = new TimeSeriesStorage(100, dataFilePath, this);

    // x轴发生变化，自动删除超出轴范围的数据点，
    QObject::connect(m_customPlot->xAxis, SIGNAL(rangeChanged(QCPRange)), this, SLOT(setDataBufferSize(QCPRange)));

}

CurvePlot::~CurvePlot()
{
    // 资源释放
    // 图表类
    if(m_customPlot) {
        m_customPlot->deleteLater();
    }

    // 停止运行
    if(m_runStatus) {
        setRunStatus(false);
    }

    // 刷新定时器
    if(m_replotTimer) {
        stopTimer();
        m_replotTimer->deleteLater();
    }

    // 数据存储器
    if(m_dataBuffer) {
        m_dataBuffer->deleteLater();
    }
}

QMap<QString, QCPGraph *> CurvePlot::Curvers() const
{
    return m_Curvers;
}

void CurvePlot::setCurvers(const QMap<QString, QCPGraph *> &Curvers)
{
    m_Curvers = Curvers;
}

QCPGraph *CurvePlot::addCurver(const QString &curverName)
{
    // 判断曲线是否已存在
    if(m_Curvers.size() > 0) {
        if(m_Curvers.contains(curverName)) {
            qDebug() << m_name << QString(" %1 已存在.").arg(curverName);
            return Q_NULLPTR;
        }
    }

    // 添加曲线
    QCPGraph *newGraph = m_customPlot->addGraph(); // 添加一条Graph
//    int index = m_customPlot->graphCount() - 1;//当前Graph数量-1

    /** 配置画笔，颜色 */
    QPen pen;
    QColor color = randomBackgroundColor(220, 200); // 70%透明度
    pen.setWidth(2);// 设置画笔线条宽度  /** 默认宽度 < 2，性能最优 */
    pen.setColor(color);// 设置画笔颜色

    newGraph->setPen(pen);// 设置画笔
    newGraph->setBrush(Qt::NoBrush); // 完全关闭填充
//    newGraph->setBrush(QBrush(QColor(0, 0, 255, 20))); //设置曲线画刷背景填充
    newGraph->setName(curverName);   // 设置Graph名称

//    newGraph->setLineStyle((QCPGraph::LineStyle)1);//曲线画笔
    newGraph->setLineStyle(QCPGraph::lsLine);//直线样式
    newGraph->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssNone,5));//曲线形状

    // 关闭抗锯齿，提高渲染速度
    newGraph->setAntialiased(false);  // 关闭线条抗锯齿
    newGraph->setAntialiasedFill(false); // 关闭填充抗锯齿
    m_customPlot->setNotAntialiasedElements(QCP::aeAll);  // 全局关闭非必要抗锯齿

    // 定时器默认开启
    startTimer();

    // 添加曲线信息
    m_Curvers.insert(curverName, newGraph);

    // 刷新
    replotQueue();

    // 返回Graph
    return newGraph;
}

void CurvePlot::removeCurver(const QString &curverName)
{
    // 为空的情况
    if(m_Curvers.isEmpty()) {
        qDebug() << "removeCurver<错误>：空，没用可删除的数据";
        return;
    }
    // 查询是否存在
    if(!m_Curvers.contains(curverName)) {
        qDebug() << "removeCurver<错误>：没找到删除的";
        return;
    }

    // 获取当前曲线列表
    // 移除数据
    m_Curvers.remove(curverName);// 移除Graph

    // 移除绑定模型数据



    // 删除Graph曲线数据
    QCustomPlot *customPlot = m_customPlot;
    int count = customPlot->graphCount();//获取曲线条数
    for(int i=0;i<count;++i)
    {
        qDebug() << QString("graph(%1): %2").arg(i).arg(customPlot->graph(i)->name());
        if(customPlot->graph(i)->name() == curverName) {
            customPlot->removeGraph(i);
            break;
        }
    }

    // 图表是否清空
    if(m_Curvers.isEmpty()) {
        setRunStatus(false);    // 停止
        emit dataEmptied(this);
    }


    // 更新曲线菜单列表


    // 刷新
    replotQueue();
}

void CurvePlot::addData(const QString &curverName, const double &x, const double &y)
{
    // 获取Graph
    QCPGraph *graph = m_Curvers.value(curverName);
    if(!graph) {
        qDebug() << "addData<CurvePlot>：没有找到曲线数据";
        return;
    }

    // 添加数据
    graph->addData(x, y);

    // 刷新
    replotQueue();
}

void CurvePlot::addData(const QString &curverName, const QVector<double> &x, const QVector<double> &y)
{
    // 获取Graph
    QCPGraph *graph = m_Curvers.value(curverName);
    if(!graph) {
        qDebug() << "addData<CurvePlot>：没有找到曲线数据";
        return;
    }
    // 添加数据
    graph->addData(x, y);

    // 刷新
    replotQueue();
}

// 获取图表的曲线信息
QVariantMap CurvePlot::getCurveInfo() const
{
    QVariantMap curvePlotInfo;

    for(const QString &curveName : m_Curvers.keys()) {
        static int index = 0;
        curvePlotInfo.insert(QString::number(index), curveName);
    }
    return curvePlotInfo;
}

void CurvePlot::removeAll()
{
    m_customPlot->clearGraphs();// 清空图表中的曲线

    m_Curvers.clear();// 清空存储的曲线数据

    // 数据是否清空
    if(m_Curvers.isEmpty()) {
        emit dataEmptied(this);
    }
}

void CurvePlot::startTimer()
{

    if(!m_replotTimer->isActive())
    {
        // 启动定时器
        m_replotTimer->start(m_intervalTime);
    }

}

void CurvePlot::stopTimer()
{
    if(m_replotTimer->isActive())
    {
        m_replotTimer->stop();
//        m_startAction->setText(QString("开始统计"));
    }
}

void CurvePlot::setRunStatus(bool status)
{
    m_runStatus = status;

    if(status) {
        startTimer(); // 启动
        QCustomPlot *customPlot = m_customPlot;
        customPlot->setInteractions(QCP::iRangeDrag|QCP::iRangeZoom| QCP::iSelectAxes );
        // 将图形的选择与相应图例项的选择同步取消
        for (int i=0; i<customPlot->graphCount(); ++i)
        {
            QCPGraph *graph = customPlot->graph(i);
            QCPPlottableLegendItem *item = customPlot->legend->itemWithPlottable(graph);
            if (item->selected() || graph->selected())
            {
                item->setSelected(false);
                QCPDataSelection select;
                graph->setSelection(select);
            }
        }
    } else {
        stopTimer();  // 停止
        m_customPlot->setInteractions(QCP::iRangeDrag|QCP::iRangeZoom| QCP::iSelectAxes | QCP::iSelectLegend | QCP::iSelectPlottables);
    }
}

bool CurvePlot::adjustXAxisRange(QCustomPlot* customPlot, double xValue, bool autoRefresh)
{
    if (!customPlot) return false;

    // 获取当前轴范围
    const auto& xRange = customPlot->xAxis->range();
    const double currentMax = xRange.upper;
    const double currentMin = xRange.lower;

    // 判断是否需要滚动
    if (xValue > currentMax) {
        const double rangeSize = currentMax - currentMin;
        customPlot->xAxis->setRange(xValue - rangeSize, xValue);

        // 可选自动刷新
        if (autoRefresh) {
            replotQueue();
        }
        return true;
    }
    return false;
}

void CurvePlot::injectionData()
{
#if 0
    QList<QString> graphs = m_Curvers.keys();
    static double x = 0;
    double y;
    x = x+1;
    // 生成随机数据
    for(int i = 0; i < graphs.size(); i++){
        y = static_cast<double>(QRandomGenerator::global()->bounded(-100, 100));
        qDebug() << "随机生成：" << y;
        y = static_cast<double>((i * 0.5) * qSin(y));
        qDebug() << "sin：" << y;
        addData(graphs.at(i), x, y);
        qDebug() << "x:" << x << ", y:" << y;
    }
#else
    static double phase = 0, x = 0;
    const double amplitude = 100.0, frequency = 2.0, sample_rate = 100.0;

    phase += 2 * M_PI * frequency / sample_rate;
    if (phase > 2*M_PI) phase -= 2*M_PI;

    x = x+1;// 模拟系统时间戳


    QMap<double, double> AxisData;
    QList<QString> graphs = m_Curvers.keys();
    for(int i = 0; i < graphs.size(); i++) {
        double y_offset = i * 0.5 * M_PI; // 多通道相位差
        double y = amplitude * qFastSin(phase + y_offset);// + x
        QString graphName = graphs.at(i);

        m_dataBuffer->addData(graphName, x, y);

    }
#endif
}


// 定时器刷新
void CurvePlot::replotTimer_timeout()
{
    // 获取生成数据
    injectionData();

    // 从队列里取出数据
    QList<TimeSeriesStorage::TimePoint> dataBuf(m_dataBuffer->getUnprocessedData());

    double x, y;
    for(const TimeSeriesStorage::TimePoint &point : dataBuf) {
        for(const QString &graphName : point.values.keys()) {
            x = point.timestamp;
            y = point.values.value(graphName);
            addData(graphName, x, y);
//            m_Curvers.value(graphName)->addData(x, y);
        }

        // 判断是否需要滚动
        adjustXAxisRange(m_customPlot, x, false);
    }

    m_customPlot->yAxis->rescale(true);// y轴自适应

    replotQueue();// 刷新图表
}


void CurvePlot::selectionChanged()
{
    QCustomPlot *customPlot = m_customPlot;

    // make top and bottom axes be selected synchronously, and handle axis and tick labels as one selectable object:
    if (customPlot->xAxis->selectedParts().testFlag(QCPAxis::spAxis) || customPlot->xAxis->selectedParts().testFlag(QCPAxis::spTickLabels) ||
        customPlot->xAxis2->selectedParts().testFlag(QCPAxis::spAxis) || customPlot->xAxis2->selectedParts().testFlag(QCPAxis::spTickLabels))
    {
        customPlot->xAxis2->setSelectedParts(QCPAxis::spAxis|QCPAxis::spTickLabels);
        customPlot->xAxis->setSelectedParts(QCPAxis::spAxis|QCPAxis::spTickLabels);
    }
    // make left and right axes be selected synchronously, and handle axis and tick labels as one selectable object:
    if (customPlot->yAxis->selectedParts().testFlag(QCPAxis::spAxis) || customPlot->yAxis->selectedParts().testFlag(QCPAxis::spTickLabels) ||
        customPlot->yAxis2->selectedParts().testFlag(QCPAxis::spAxis) || customPlot->yAxis2->selectedParts().testFlag(QCPAxis::spTickLabels))
    {
        customPlot->yAxis2->setSelectedParts(QCPAxis::spAxis|QCPAxis::spTickLabels);
        customPlot->yAxis->setSelectedParts(QCPAxis::spAxis|QCPAxis::spTickLabels);
    }

    // 将图形的选择与相应图例项的选择同步
    for (int i=0; i<customPlot->graphCount(); ++i)
    {
        QCPGraph *graph = customPlot->graph(i);
        QCPPlottableLegendItem *item = customPlot->legend->itemWithPlottable(graph);
        if (item->selected() || graph->selected())
        {
            item->setSelected(true);
            // 注意：这句需要Qcustomplot2.0系列版本
            graph->setSelection(QCPDataSelection(graph->data()->dataRange()));
            // 这句1.0系列版本即可
            // graph->setSelected(true);
        }
    }
}

void CurvePlot::setDataBufferSize(const QCPRange &range)
{
    double newPoint = range.upper;
    double oldPoint = range.lower;
    double dataBufSize = newPoint - oldPoint;   // 区间范围
    double plotBuffer = dataBufSize * 1.7;// 留70%缓冲防止突然缩放

//    qDebug() << "x轴新范围:" << oldPoint << "到" << newPoint << "    区间范围(显示的x数据点数量):" << dataBufSize;

    m_dataBuffer->setTimeWindow(dataBufSize);// 设置数据存储区范围大小，超出范围就会写入到文件

    // 清除超出x轴范围的数据点
    for(QCPGraph *graph : m_Curvers) {
        QCPDataContainer<QCPGraphData>* container = graph->data().data();
//        Q_ASSERT(container->isDataSortedByKey());  // 运行时检查排序
        container->removeBefore(oldPoint - plotBuffer);  // 删除左侧不可见数据
//        container->removeAfter(newPoint + plotBuffer); // 删除右侧不可见数据
        graph->data()->set(QCPDataContainer<QCPGraphData>(*container)); // 触发轻量级数据更新
    }
}

void CurvePlot::replotQueue(bool b)
{
    if(b) {
        m_customPlot->replot(QCustomPlot::rpQueuedReplot);// 重绘队列，防止频繁刷新，导致卡顿
    } else {
        m_customPlot->replot(); // 立即刷新
    }
}

QString CurvePlot::name() const
{
    return m_name;
}

void CurvePlot::setName(const QString &name)
{
    m_name = name;

    m_customPlot->xAxis2->setLabel(m_name);
}



QCustomPlot *CurvePlot::customPlot() const
{
    return m_customPlot;
}

void CurvePlot::setCustomPlot(QCustomPlot *customPlot)
{
    m_customPlot = customPlot;
}

